
`include "alu_defs.v"

`timescale 1ns / 1ps


module alu(
	i_cin,
	i_func,
	i_op_a,
	i_op_b,
	
	o_cout,
	o_zero,
	o_ovf,
	o_sign,
	o_rez
);

parameter DATA_WIDTH	= 32;

input i_cin;

input [`ALU_FUNC_WIDTH-1:0] i_func;
input [DATA_WIDTH-1:0] i_op_a;
input [DATA_WIDTH-1:0] i_op_b;

output o_cout;
reg o_cout;

output o_zero;
output o_ovf;
output o_sign;

output [DATA_WIDTH-1:0] o_rez;
reg [DATA_WIDTH-1:0] o_rez;

always@( i_cin or i_func or i_op_a or i_op_b )
begin
	case( i_func )
		`ALU_FUNC_ADD  : { o_cout, o_rez } = i_op_a + i_op_b + i_cin;
		`ALU_FUNC_SUBA : { o_cout, o_rez } = i_op_a - i_op_b - i_cin;
		`ALU_FUNC_SUBB : { o_cout, o_rez } = i_op_b - i_op_a - i_cin;
		`ALU_FUNC_OR   : { o_cout, o_rez } = { 1'b0, i_op_a | i_op_b };
		`ALU_FUNC_AND  : { o_cout, o_rez } = { 1'b0, i_op_a & i_op_b };
		`ALU_FUNC_NOTAB: { o_cout, o_rez } = { 1'b0, (~i_op_a) & i_op_b };
		`ALU_FUNC_EXOR : { o_cout, o_rez } = { 1'b0, i_op_a ^ i_op_b };
		`ALU_FUNC_EXNOR: { o_cout, o_rez } = { 1'b0, ~(i_op_a ^ i_op_b) };
	endcase
end

assign o_zero = ~(|o_rez);

assign o_sign = o_rez[DATA_WIDTH-1];

assign o_ovf =  o_rez[DATA_WIDTH-1] ^ o_rez[DATA_WIDTH-2];

endmodule
